/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.eng.scc.core.conn.serial;

import com.eng.scc.core.db.manager.service.FuelControllerManagerService;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Date;
import java.util.Calendar;
import java.util.HashMap;

/**
 *
 * @author Rafael
 */
public class RXTX
{
    private final HashMap<Integer,ProtocolData> activeDevices = new HashMap<Integer,ProtocolData>();
    
    public class SerialReader implements SerialPortEventListener
    {
        private InputStream in = null;
        private OutputStream out = null;

        public SerialReader( InputStream in, OutputStream out )
        {
            this.in = in;
            this.out = out;
        }

        @Override
        public void serialEvent( SerialPortEvent arg0 )
        {
            StringBuilder buffer = new StringBuilder();

            short readed;

            switch ( arg0.getEventType() )
            {
                case SerialPortEvent.BI:
                case SerialPortEvent.OE:
                case SerialPortEvent.FE:
                case SerialPortEvent.PE:
                case SerialPortEvent.CD:
                case SerialPortEvent.CTS:
                case SerialPortEvent.DSR:
                case SerialPortEvent.RI:
                case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
                    break;
                case SerialPortEvent.DATA_AVAILABLE:
                    //Read all input...
                    while ( true )
                    {
                        try
                        {
                            readed = (short) in.read(); // 1 byte

                            if ( readed == -1 )
                            {
                                break;
                            }

                            //sempre receberá 1 byte;
                            buffer.append( String.format( "%02X", readed ) );

                            //if ( debug )
                            System.err.print( "0x" + String.format("%02X", readed ) + " " );
                        }

                        catch ( IOException ioe )
                        {
                            System.out.println( "erro reading: " + ioe );
                        }
                    }

                    System.out.println();
                    
                    try
                    {
                        in.close();
                    }
                    catch ( IOException ex )
                    {
                        ex.printStackTrace();
                    }
                    
                    decodeProtocol( buffer );

                    break;
            }
        }

        private void decodeProtocol( StringBuilder buffer )
        {
            try
            {
                if ( buffer.length() > 2 )
                {
                    int serial = Integer.parseInt( buffer.substring( 0, 4 ) );

                    if ( checksum( buffer ) )
                    {
                        ProtocolData data = null;

                        if ( ( data = activeDevices.get( serial ) ) == null )
                        {
                            data = new ProtocolData();

                            data.setSerial( serial );
                        }

                        Short[] val = null;
                        int start = 6;
                        int end = start + 2;

                        switch ( Short.parseShort( buffer.substring( 4, 6 ) ) )
                        {
                            case 1:
                                data.setCarrying( Short.parseShort( buffer.substring( start, end + 2 ), 16 ) );

                                activeDevices.put( serial, data );

                                break;
                            case 2:

                                val = new Short[6];

                                for ( int i = 0; i < val.length; i++, start += 2, end += 2 )
                                {
                                    val[i] = Short.parseShort( buffer.substring( start, end ), 16 );
                                }

                                Calendar c = Calendar.getInstance();
                                c.set( Calendar.SECOND, 0 );
                                c.set( Calendar.MILLISECOND, 0 );
                                c.set( Calendar.MINUTE, val[5] );
                                c.set( Calendar.HOUR_OF_DAY, val[4] );
                                c.set( Calendar.YEAR, Integer.valueOf( val[2] + "" + val[3]) );
                                c.set( Calendar.MONTH, val[1] - 1 );
                                c.set( Calendar.DAY_OF_MONTH, val[0] );

                                data.addFuelDate( new Date( c.getTimeInMillis() ) );

                                break;

                            case 3:
                                val = new Short[10];

                                for ( int i = 0; i < val.length; i++, start += 2, end += 2 )
                                {
                                    val[i] = Short.parseShort( buffer.substring( start, end ), 16 );
                                }

                                data.addFuelValue( val );
                                data.setSum( data.getSum() + val.length );

                                break;
                            case 4:
                                val = new Short[Short.parseShort( buffer.substring( start, end ), 16 )];
                                start = 8;
                                end = start + 2;

                                for ( int i = 0; i < val.length; i++, start += 2, end += 2 )
                                {
                                    val[i] = Short.parseShort( buffer.substring( start, end ), 16 );
                                }

                                data.addFuelValue( val );
                                data.setSum( data.getSum() + val.length );

                                break;
                            case 5:

                                //Neste fim de transmissão deve-se inserir os dados no banco, após validado checksum

                                short sum = Short.parseShort( buffer.substring( start, end + 2 ), 16 );

                                ProtocolData protocolData = activeDevices.remove( serial );

//                                if ( sum == data.getSum() )
                                if ( true )
                                {
                                    //ok, transmissão do device finalizada

                                    try
                                    {
                                        FuelControllerManagerService.getInstance().addDeviceInfos( protocolData );
                                        out.write( 1 );
                                    }

                                    catch ( Exception e )
                                    {
                                        e.printStackTrace();

                                        out.write( 0 );
                                    }                                
                                }

                                else
                                {
                                    out.write( 0 );
                                }

                                out.close();

                                break;
                        }
                    }

                    else
                    {
                        activeDevices.remove( serial );

                        out.write( 0 );
                        out.close();
                    }
                }
            }
            
            catch ( Exception e )
            {
                e.printStackTrace();
            }
        }
        
        private boolean checksum( StringBuilder buffer )
        {
            int start = 0;
            int end = 2;
            
            int data = 0;
            
            for ( int i = 0; i < (buffer.length() - 4) / 2; i++ )
            {
                data += Short.parseShort( buffer.substring( start, end), 16 );
                
                start = end;
                end += 2;
            }
            
            int checkSum = Integer.parseInt( buffer.substring( start, buffer.length()), 16 );
            
//            return data == checkSum;
            return true;
        }
    }
}
